//
// Created by Administrator on 2021/11/23.
//

#ifndef RAY_CASTING_RAYCASTING_H
#define RAY_CASTING_RAYCASTING_H


#include "Volume.h"

const double EPSILON = 0.000001;

class RayCasting {
    // 旋转矩阵
    float R[9]{};
    // 平移向量 (要根据R调整，以保证获得体数据全貌)
    float T[3]{0, 0, 450};
    // 视点位置
    float eye[3]{0.5, 0.5, 1};
    // 物体参考点位置
    float center[3]{0, 0, 0};
    // 相机朝上的方向
    float up[3]{0, 1, 0};
    // 渲染的向量
    float *rgba;

    Volume *volume;

    /**
     * 求取从图像空间到物体空间变换的旋转矩阵
     */
    void rotation_matrix();

    /**
     * 判断点是否在包围盒内
     * @param point 具体的点坐标
     * @return
     */
    bool check_in_box(const float *point);

    /**
     * 判断投射光线与包围盒是否相交 (若相交，求靠近视点处的交点坐标)
     * 将包围盒 6 个面无限扩展, 并分成 3 组, 即平行于 XOY, YOZ, ZOX 平面的各有 2 个;
     * 求光线与 6 个平面的交点, 从每组的 2 个交点中选出距离视点较近者, 这样得到 3 个候选交点;
     * 从这 3 个候选交点中选出距离视点最远的
     * 最后判断这个点是否落在包围盒内，若在，即为光线与包围盒的靠近视点处的交点
     *
     * @param startPos 靠近视点处的交点坐标
     * @param pos 光线起点坐标
     * @param dir 光线方向向量
     * @return
     */
    bool intersection(float *startPos, const float *pos, const float *dir);

    /**
     * 三线性插值
     * @param sampleColor 插值结果
     * @param pos 采样点坐标
     */
    void tr_interpolation(float *sampleColor, const float *pos);

    /**
     * 合成像素值
     * @param temp 合成颜色值
     * @param x 二维图像像素坐标
     * @param y 二维图像像素坐标
     */
    void composite(float *temp, int x, int y);

public:
    explicit RayCasting(Volume *volume);

    ~RayCasting();

    float *get_rgba() {
        return rgba;
    }

    void exec() {
        float *linePS = get_rgba();
        for (int j = 0; j < 500; j++) {
            // 逐个合成像素值
            for (int i = 0; i < 400; i++) {
                composite(linePS, i, j);
                linePS += 4;
            }
        }
    }
};


#endif //RAY_CASTING_RAYCASTING_H
